package com.hanxiaozhang.threadbase1ndedition.no4lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 〈一句话功能简述〉<br>
 * 〈ReentrantLock的基本使用〉
 * <p>
 * ReentrantLock可用于替代synchronized，
 * 但ReentrantLock必须要必须要必须要手动释放锁。
 * Tips：
 * 使用synchronized锁定遇到异常，jvm会自动释放锁，
 * 但是ReentrantLock必须手动释放锁，因此要在finally中进行锁的释放
 * <p>
 * method3() 常用方法解释
 *
 * @author hanxinghua
 * @create 2021/11/11
 * @since 1.0.0
 */
public class No1ReentrantLockBase {

    private ReentrantLock lock = new ReentrantLock();

    Condition condition = lock.newCondition();

    public void method1() {
        // synchronized(this)
        lock.lock();
        try {
            for (int i = 0; i < 10; i++) {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void method2() {
        lock.lock();
        try {
            System.out.println("method2 ...");
        } finally {
            lock.unlock();
        }

    }

    /**
     * 常用方法解释
     */
    public void method3() {

        // 查询当前线程保持此锁定的个数，调用lock方法的次数
        lock.getHoldCount();
        // 返回正等待获取此锁定线程的估计数
        lock.getQueueLength();
        // 返回等待与锁定相关的给定条件线程的估计数
        lock.getWaitQueueLength(condition);
        // 查询指定的线程是否有正在等待获取次锁定
        lock.hasQueuedThread(new Thread());
        // 查询是否有线程正在等待获取次锁定
        lock.hasQueuedThreads();
        // 查询是否有线程正在等待此锁有关的条件
        lock.hasWaiters(condition);
        // 判断是不是公平锁
        lock.isFair();
        // 查询当前线程是否保存此锁定
        lock.isHeldByCurrentThread();
        // 查询此锁定是否有任意线程保持
        lock.isLocked();

    }

    public static void main(String[] args) {
        No1ReentrantLockBase example = new No1ReentrantLockBase();
        new Thread(example::method1).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        example.method3();

        new Thread(example::method2).start();
    }

}
